﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using md.imi.membrane.common.Interfaces;

namespace md.imi.membrane.common.Messaging
{
    /// <summary>
    ///  Manager behavior:
    ///     1. It buffers a predefined number of messages. in order to pass them to 
    /// the newly registered consumer (User View) .
    ///     2. When a view (listener ) has been registered, 
    /// </summary>
    public class MessagesManager
    {
        private const int MaxMessagesCount = 100;

        /// <summary>
        ///     A list of registered listeners, wihch implements the IMessageViewer interface.
        /// The list is scanned to determine newly received message destination
        /// </summary>
        private List<IMessageViewer> listeners = new List<IMessageViewer>();

        /// <summary>
        ///      A list of cashed received messages.
        /// </summary>
        private List<MessageData> messages = new List<MessageData>();

        /// <summary>
        ///     lock object used for safe interthread call.
        /// </summary>
        private readonly object lockObject = new object();


        /// <summary>
        ///     Add a listerner of a certain type. When a Listener is 
        /// added, the cach is searched for existing messages for this 
        /// type of listener, and they are passed one by one to the listener
        /// </summary>
        /// <param name="listener"></param>
        public void RegisterListener(IMessageViewer listener)
        {
            lock (lockObject)
            {
                // do not add twice the same listener
                if (listeners.Any(l => l == listener))
                {
                    return;
                }
                
                listeners.Add(listener);

                // search for cached messages sent for this listener
                foreach (var m in messages)
                {
                    if (listener.GetType() == m.Destination.GetType())
                    {
                        listener.AddMessage(m);
                    }
                }
            }
            
        }

        /// <summary>
        ///             Remove listener from list by given pointer
        /// </summary>
        /// <param name="listener"></param>
        public void UnregisterListener(IMessageViewer listener)
        {
            lock (lockObject)
            {
                listeners.Remove(listener);
                listener.ClearView();
            }
        }

        /// <summary>
        ///     Add a message to cache and remove oldest if number of existing messages already 
        /// exceeds allowed limit. Also search trough registered liteners, ad forward the new message
        /// by destination type.
        ///  Of more than one listener is registered with the same type, foorward message to multiple 
        /// destinations.
        /// </summary>
        /// <param name="message"></param>
        public void AddMessage(MessageData message)
        {
            lock (lockObject)
            {
                if (messages.Count > MaxMessagesCount)
                {
                    messages.RemoveRange(0, (int) MaxMessagesCount/10);
                }

                messages.Add(message);

                foreach (var listener in listeners)
                {
                    if (listener.GetDestinationType() == message.Destination)
                    {
                        listener.AddMessage(message);
                    }
                }
            }
        }
    }


}
